package cn.funeralobjects.upms.service.impl;

import cn.funeralobjects.common.jpa.service.*;
import cn.funeralobjects.common.repository.*;
import cn.funeralobjects.common.service.annotataion.CommonService;
import cn.funeralobjects.common.service.exception.DataConflictException;
import cn.funeralobjects.common.service.validate.DataCheck;
import cn.funeralobjects.upms.entity.EUser;
import cn.funeralobjects.upms.entity.EUserCertificate;
import cn.funeralobjects.upms.enums.UserCertificateType;
import cn.funeralobjects.upms.model.UserCertificate;
import cn.funeralobjects.upms.repository.UserCertificateRepository;
import cn.funeralobjects.upms.service.UserCertificateService;
import cn.funeralobjects.upms.service.UserService;
import cn.funeralobjects.util.Assert;
import cn.funeralobjects.util.NumberUtils;
import cn.funeralobjects.util.annotation.ArgHasLength;
import cn.funeralobjects.util.annotation.ArgNonNull;
import cn.funeralobjects.util.annotation.ArgNotZero;
import cn.funeralobjects.util.annotation.AssertArg;
import org.springframework.data.repository.CrudRepository;

import javax.annotation.Resource;
import java.util.List;
import java.util.Optional;

/**
 * @author FuneralObjects
 * Create date: 2020/6/3 2:58 PM
 */
@CommonService
public class UserCertificateServiceImpl implements UserCertificateService,
        JpaModifyService<UserCertificate, EUserCertificate, Integer>,
        JpaEntityService<EUserCertificate, Integer>,
        JpaCodeService<EUserCertificate, Integer>,
        JpaEnableService<EUserCertificate, Integer>,
        JpaDelSaltService<EUserCertificate, Integer>,
        JpaCommitService<Integer> {

    @Resource
    private UserCertificateRepository userCertificateRepository;

    @Resource
    private UserService userService;

    @AssertArg
    @Override
    public void checkConflict(@AssertArg UserCertificate userCertificate) throws DataConflictException {
        DataCheck.conflictData(this.existsCertificate(userCertificate.getCert(), userCertificate.getType()), () -> createDataCode("cert-type", userCertificate.getCert() + "-" + userCertificate.getType().getCode()));
    }

    @Override
    public EUserCertificate toEntity(UserCertificate userCertificate) {
        if (userCertificate == null) {
            return null;
        }
        EUserCertificate entity = new EUserCertificate();
        EUser user = new EUser();
        user.setId(userCertificate.getUserId());
        entity.setCert(userCertificate.getCert())
                .setCode(userCertificate.getCode())
                .setType(userCertificate.getType())
                .setUser(user);
        return entity;
    }

    @Override
    public CodeRepository<EUserCertificate, Integer> codeRepository() {
        return userCertificateRepository;
    }

    @Override
    public CommitRepository<Integer> commitRepository() {
        return userCertificateRepository;
    }

    @Override
    public DelSaltRepository<EUserCertificate, Integer> delSaltRepository() {
        return userCertificateRepository;
    }

    @Override
    public EnableRepository<EUserCertificate, Integer> enableRepository() {
        return userCertificateRepository;
    }

    @Override
    public EntityRepository<EUserCertificate, Integer> entityRepository() {
        return userCertificateRepository;
    }

    @Override
    public CrudRepository<EUserCertificate, Integer> modifyRepository() {
        return userCertificateRepository;
    }

    @AssertArg
    @Override
    public void checkConflict(@AssertArg UserCertificate userCertificate, @ArgNotZero Integer withoutId) throws DataConflictException {
        DataCheck.conflictData(this.existsCertificate(userCertificate.getCert(), userCertificate.getType(), withoutId), () -> createDataCode("cert-type", userCertificate.getCert() + "-" + userCertificate.getType().getCode()));
    }

    @Override
    public void copyToEntity(UserCertificate sourceModify, EUserCertificate targetEntity) {
        targetEntity.setCert(sourceModify.getCert())
                .setCode(sourceModify.getCode())
                .setType(sourceModify.getType());
    }

    @Override
    public boolean isValid(Integer id) {
        return NumberUtils.notZero(id);
    }

    @Override
    public void validateModify(UserCertificate userCertificate) {
        Assert.argAssert(userCertificate, "userCertificate");
        userService.mustExistsById(userCertificate.getUserId());
    }

    @AssertArg
    @Override
    public boolean existsCertificate(@ArgHasLength String cert, @ArgNonNull UserCertificateType type) {
        return userCertificateRepository.existsAllByTypeAndCertAndDelSalt(type, cert, getExistsDelSalt());
    }

    @AssertArg
    @Override
    public boolean existsCertificate(@ArgHasLength String cert, @ArgNonNull UserCertificateType type, @ArgNotZero Integer withoutId) {
        return userCertificateRepository.existsAllByTypeAndCertAndDelSaltAndIdNot(type, cert, getExistsDelSalt(), withoutId);
    }

    @AssertArg
    @Override
    public Optional<EUserCertificate> findCertificate(@ArgHasLength String cert, @ArgNonNull UserCertificateType type) {
        return userCertificateRepository.findFirstByTypeAndCertAndDelSalt(type, cert, getExistsDelSalt());
    }

    @Override
    public List<EUserCertificate> findAllByUserId(Integer userId) {
        return userCertificateRepository.findAllByUser_IdAndDelSalt(userId, getExistsDelSalt());
    }

    private Integer getExistsDelSalt() {
        return (Integer) userCertificateRepository.getDefaultExistsDelSalt();
    }
}
